/*
 * Copyright (c) 2021 HPMicro
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */

#ifndef HPM_SDP_DRV_H
#define HPM_SDP_DRV_H

/**
 * @brief SDP driver APIs
 * @defgroup sdp_interface SDP driver APIs
 * @ingroup sdp_interfaces
 * @{
 *
 */

#include "hpm_common.h"
#include "hpm_sdp_regs.h"

/***********************************************************************************************************************
 * Definitions
 **********************************************************************************************************************/
/**
 * @brief SDP AES key bit options
 */
typedef enum {
    sdp_aes_keybits_128, /**< 128 bit AES key */
    sdp_aes_keybits_256, /**< 256 bit AES key */
} sdp_aes_key_bits_t;

/**
 * @brief AES operation option
 */
typedef enum {
    sdp_aes_op_encrypt, /**< AES Encrypt operation */
    sdp_aes_op_decrypt, /**< AES Decrypt operation */
} sdp_aes_op_t;

/**
 * @brief SDP HASH algorithm definitions
 */
typedef enum {
    sdp_hash_alg_sha1,   /**< SDP SHA1 */
    sdp_hash_alg_crc32,  /**< SDP CRC32 */
    sdp_hash_alg_sha256, /**< SDP SHA256 */
    sdp_hash_alg_max = sdp_hash_alg_sha256,
} sdp_hash_alg_t;

#define HASH_BLOCK_SIZE (64U)    /**< Hash block size in bytes */
#define AES_BLOCK_SIZE (16U)     /**< AES block size in bytes */
#define AES_128_KEY_SIZE (0x10U) /**< AES 128-bit key size in bytes */
#define AES_256_KEY_SIZE (0x20U) /**< AES 256-bit key size in bytes */
/**
 * @brief Bitfield definitions for the PKT_CTRL
 */
#define SDP_PKT_CTRL_DERSEMA_MASK (1U << 2)
#define SDP_PKT_CTRL_CHAIN_MASK (1U << 3)
#define SDP_PKT_CTRL_HASHINIT_MASK (1U << 4)
#define SDP_PKT_CTRL_HASHFINISH_MASK (1U << 5)
#define SDP_PKT_CTRL_CIPHIV_MASK (1U << 6)

/**
 * @brief SDP packet data structure
 */
typedef struct _sdp_packet_struct {
    struct _sdp_packet_struct *next_cmd;
    union {
        struct {
            uint32_t RESERVED0 : 1;
            uint32_t PKTINT : 1;     /**< Packet interrupt flag */
            uint32_t DCRSEMA : 1;    /**< Descrement Semaphore flag */
            uint32_t CHAIN : 1;      /**< Chain Packet flag */
            uint32_t HASHINIT : 1;   /**< Hash initialize flag */
            uint32_t HASHFINISH : 1; /**< Hash finish flag */
            uint32_t CIPHIV : 1;     /**< Cipher IV flag */
            uint32_t RESERVED1 : 17;
            uint32_t PKTTAG : 8; /**< Packet tag flag, not used */
        };
        uint32_t PKT_CTRL; /**< Packet control word */
    } pkt_ctrl;
    uint32_t src_addr; /**< Source address */
    uint32_t dst_addr; /**< Destination address */
    uint32_t buf_size; /**< Data buffer size in bytes */
    uint32_t reserved[3];
} sdp_pkt_struct_t;

/**
 * @brief SDP AES context structure
 */
typedef struct {
    uint8_t key_idx;  /**< AES key index */
    uint8_t key_bits; /**< AES key bits */
    uint16_t reserved;
    sdp_pkt_struct_t sdp_pkt;                         /**< SDP packet for AES operation */
    uint32_t buf0[AES_BLOCK_SIZE / sizeof(uint32_t)]; /**< buf0 */
    uint32_t buf1[AES_BLOCK_SIZE / sizeof(uint32_t)]; /**< buf1 */
    uint32_t buf2[AES_BLOCK_SIZE / sizeof(uint32_t)]; /**< buf2 */
    uint32_t buf3[AES_BLOCK_SIZE / sizeof(uint32_t)]; /**< buf3 */
} sdp_aes_ctx_t;

/**
 * @brief SDP DMA context
 */
typedef struct {
    sdp_pkt_struct_t sdp_pkt; /**< SDP packet for DMA operation (memset/memcpy) */
} sdp_dma_ctx_t;

/**
 * @brief SDP HASH context
 */
typedef struct {
    sdp_pkt_struct_t sdp_pkt; /**< SDP packet for HASH operation */
    uint32_t internal[64];    /**< internal buffer */
} sdp_hash_ctx_t;

/**
 * @brief SDP error status definitions
 */
enum {
    status_sdp_no_crypto_support = MAKE_STATUS(status_group_sdp, 0), /**< The crypto algorithm is not supported */
    status_sdp_no_hash_support = MAKE_STATUS(status_group_sdp, 1),   /**< The hash algorithm is not supported */
    status_sdp_invalid_key_src = MAKE_STATUS(status_group_sdp, 2),   /**< Invalid AES key source */
    status_sdp_error_packet = MAKE_STATUS(status_group_sdp, 3),      /**< Error packet */
    status_sdp_aes_busy = MAKE_STATUS(status_group_sdp, 4),          /**< AES engine is busy */
    status_sdp_hash_busy = MAKE_STATUS(status_group_sdp, 5),         /**< HASH engine is busy */
    status_sdp_error_setup = MAKE_STATUS(status_group_sdp, 6),       /**< Error setup in SDP IP */
    status_sdp_error_src = MAKE_STATUS(status_group_sdp, 7),         /**< Error source address */
    status_sdp_error_dst = MAKE_STATUS(status_group_sdp, 8),         /**< Error destination address */
    status_sdp_error_hash = MAKE_STATUS(status_group_sdp, 9),        /**< Error Hash digest */
    status_sdp_error_chain = MAKE_STATUS(status_group_sdp, 10),      /**< Error packet chain */
    status_sdp_error_invalid_mac,                                    /**< Inavlid Message Athenticaion Code (MAC) */

};

#ifdef __cplusplus
extern "C"
{
#endif


/***********************************************************************************************************************
 * Prototypes
 **********************************************************************************************************************/
    /**
     * @brief Initialize the SDP controller
     * @param [in] base SDP base address
     * @retval API execution status.
     */
    hpm_stat_t sdp_init(SDP_Type * base);

    /**
     * @brief De-initialize the SDP controller
     * @param [in] base SDP base address
     * @retval API execution status.
     */
    hpm_stat_t sdp_deinit(SDP_Type *base);

    /**
     * @brief Set the AES key for the SDP AES operation
     * @param [in] base SDP base address
     * @param [in] aes_ctx AES operation context
     * @param [in] key AES key
     * @param [in] key_bits AES key-bit option
     * @param [in] key_idx AES key index
     * @retval API execution status.
     */
    hpm_stat_t sdp_aes_set_key(SDP_Type *base, sdp_aes_ctx_t *aes_ctx, const uint8_t *key, sdp_aes_key_bits_t key_bits,
                               uint32_t key_idx);

    /**
     * @brief Perform the basic AES ECB operation
     * @param [in] base SDP base address
     * @param [in] aes_ctx AES operation context
     * @param [in] op AES operation option
     * @param [in] len AES data length in bytes
     * @param [in] in Input buffer
     * @param [out] out Output buffer
     * @retval API execution status.
     */
    hpm_stat_t sdp_aes_crypt_ecb(SDP_Type *base, sdp_aes_ctx_t *aes_ctx, sdp_aes_op_t op, uint32_t len, const uint8_t *in,
                                 uint8_t *out);

    /**
     * @brief Perform the AES CBC operation
     * @param [in] base SDP base address
     * @param [in] aes_ctx AES operation context
     * @param [in] op AES operation option
     * @param [in] length AES data length in bytes
     * @param [in] iv Initial vector/nonce
     * @param [in] input Input buffer
     * @param [out] output Output buffer
     * @retval API execution status.
     */
    hpm_stat_t sdp_aes_crypt_cbc(SDP_Type *base, sdp_aes_ctx_t *aes_ctx, sdp_aes_op_t op, uint32_t length,
                                 const uint8_t iv[16], const uint8_t *input, uint8_t *output);

    /**
     * @brief Perform the AES-CTR operation
     *        See NIST Special Publication800-38A for more details
     * @param [in] base SDP base address
     * @param [in] aes_ctx AES operation context
     * @param [in] nonce_counter AES-CTR nounce/counter
     * @param [in] input Input buffer
     * @param [out] output Output buffer
     * @param [in] length Length of data for AES-CTR operation
     * @retval API execution status.
     */
    hpm_stat_t sdp_aes_crypt_ctr(SDP_Type *base, sdp_aes_ctx_t *aes_ctx, uint8_t *nonce_counter, uint8_t *input,
                                 uint8_t *output, uint32_t length);

    /**
     * @brief Perform the AES-CCM generate and encrypt
     *        See NIST Special Publication 800-38C for more details
     * @param [in] base SDP base address
     * @param [in] aes_ctx AES operation context
     * @param [in] input_len Input data length in bytes
     * @param [in] iv Initial vector
     * @param [in] iv_len Initial vector length in bytes
     * @param [in] aad Additional Authentication data
     * @param [in] aad_len Additional authentication data size
     * @param [in] input Input data buffer
     * @param [out] output Output buffer
     * @param [out] tag MAC buffer
     * @param [in] tag_len Tag/MAC size in bytes
     * @retval API execution status.
     */
    hpm_stat_t sdp_aes_ccm_generate_encrypt(SDP_Type *base, sdp_aes_ctx_t *aes_ctx, uint32_t input_len, const uint8_t *iv,
                                            uint32_t iv_len, const uint8_t *aad, uint32_t aad_len, const uint8_t *input,
                                            uint8_t *output, uint8_t *tag, uint32_t tag_len);

    /**
     * @brief Perform the AES-CCM decrypt and verify
     *        See NIST Special Publication 800-38C for more details
     * @param [in] base SDP base address
     * @param [in] aes_ctx AES operation context
     * @param [in] input_len Input data length in bytes
     * @param [in] iv Initial vector
     * @param [in] iv_len Initial vector length in bytes
     * @param [in] aad Additional Authentication data
     * @param [in] aad_len Additional authentication data size
     * @param [in] input Input data buffer
     * @param [out] output Output buffer
     * @param [in] tag MAC buffer
     * @param [in] tag_len Tag/MAC size in bytes
     * @retval API execution status.
     */
    hpm_stat_t sdp_aes_ccm_decrypt_verify(SDP_Type *base, sdp_aes_ctx_t *aes_ctx, uint32_t input_len, const uint8_t *iv,
                                          uint32_t iv_len, const uint8_t *aad, uint32_t aad_len, const uint8_t *input,
                                          uint8_t *output, const uint8_t *tag, uint32_t tag_len);

    /**
     * @brief Perform the DMA accelerated memcpy
     * @param [in] base SDP base address
     * @param [in] sdp_ctx SDP DMA context
     * @param [out] dst Destination address for memcpy operation
     * @param [in] src Source address for memcpy operation
     * @param [in] length Length of the data to be copied
     * @retval API execution status.
     */
    hpm_stat_t sdp_memcpy(SDP_Type *base, sdp_dma_ctx_t *sdp_ctx, void *dst, const void *src, uint32_t length);

    /**
     * @brief Perform the DMA accelerated memset
     * @param [in] base SDP base address
     * @param [in] sdp_ctx SDP DMA context
     * @param [out] dst SDP destination address for memset operation
     * @param [in] pattern pattern for memset operation
     * @param [in] length length of the memory for memset operation
     * @retval API execution status.
     */
    hpm_stat_t sdp_memset(SDP_Type *base, sdp_dma_ctx_t *sdp_ctx, void *dst, uint8_t pattern, uint32_t length);

    /**
     * @brief Initialize the HASH engine
     * @param [in] base SDP base address
     * @param [in] hash_ctx HASH operation context
     * @param [in] alg Hash algorithm
     * @retval API execution status. status_success or status_invalid_argument
     */
    hpm_stat_t sdp_hash_init(SDP_Type *base, sdp_hash_ctx_t *hash_ctx, sdp_hash_alg_t alg);

    /**
     * @brief Compute the HASH digest
     * @param [in] base SDP base address
     * @param [in] hash_ctx HASH operation context
     * @param [in] data Data for HASH computing
     * @param [in] length Data size for HASH computing
     * @retval API execution status.
     */
    hpm_stat_t sdp_hash_update(SDP_Type *base, sdp_hash_ctx_t *hash_ctx, const uint8_t *data, uint32_t length);

    /**
     * @brief Finish the HASH calculation and output the digest
     * @param [in] base SDP base address
     * @param [in] hash_ctx HASH operation context
     * @param [out] digest  Digest buffer
     * @retval API execution status.
     */
    hpm_stat_t sdp_hash_finish(SDP_Type *base, sdp_hash_ctx_t *hash_ctx, uint8_t *digest);

    /**
     * @brief Wait until the SDP operation gets done
     * @retval API execution status.
     */
    hpm_stat_t sdp_wait_done(SDP_Type *base);

#ifdef __cplusplus
}
#endif

/**
 * @}
 */

#endif /* HPM_SDP_DRV_H */
